package ngat.oss.util;

import ngat.oss.*;
import ngat.phase2.*;
import ngat.phase2.nonpersist.*;
import ngat.util.*;
import ngat.astrometry.*;

import java.io.*;
import java.util.*;
import java.text.*;

import jyd.dbms.*;
import jyd.storable.*;
import jyd.collection.*;


public class JYDRAHist {
    
    public static void main (String[] args) {
	
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
	SimpleTimeZone   UTC = new SimpleTimeZone(0,"UTC");
	sdf.setTimeZone(UTC);

	try {
	    
	    CommandTokenizer parser = new CommandTokenizer("--");
	    parser.parse(args);
	    ConfigurationProperties config = parser.getMap();
	    
	    // mid-day of first night to test
	    long start = (sdf.parse(config.getProperty("start"))).getTime();
	  
	    double lat = config.getDoubleValue("lat");
	    double lon = config.getDoubleValue("long");
	    
	    Position.setViewpoint(Math.toRadians(lat), Math.toRadians(lon));
	    Site site = new Site("Test", lat, lon);

	    String dbDirName = System.getProperty("db.dir");
	    String dbRootName = System.getProperty("db.name");

	    OSS_Utilities.setDatabaseDir(new File(dbDirName));
	    OSS_Utilities.setRootName(dbRootName);
	    
	    System.err.println("Using: DB: "+dbRootName+" in dir: "+dbDirName);
	    
	    Transaction t = Transaction.current();
	    
	    Root root = OSS_Utilities.fetchRoot();
	    
	    // Check it exists.
	    if (root == null) {		
		System.err.println("Root: Not in database.");
		return;
	    } 
	 
	    double[] rah = new double[36];
	    for (int i = 0; i < 36; i++) {
		rah[i] = 0.0;
	    }
		
	    long sod = start;
	    
	    // length of night.
	    Position sun = Astrometry.getSolarPosition(sod);
	    
	    long ln = 0L;
	    long st = sod;
	    while (st < sod + 86400*1000L) {
		double sunElev = sun.getAltitude(st, site);
		if (sunElev < Math.toRadians(-18.0))
		    ln += 60000L;
		    st += 60000L;
	    }
	    double lnight = (double)ln;
	    
	    // record exec per date
	    double time = 0.0;

	    Iterator iTag = root.listAllTags();
	    while (iTag.hasNext()) {
		
		Tag tag = (Tag)iTag.next();
		
		Iterator iUser = tag.listAllUsers();
		while (iUser.hasNext()) {
		    
		    User user = (User)iUser.next();
		    
		    Iterator iProp = user.listAllProposals();
		    while (iProp.hasNext()) {
			
			KVPair pair = (KVPair)iProp.next();
			String name = (String)pair.getKey();
			Path   path = new Path(user.getFullPath(), name);
			Proposal proposal = null;
			try {
			    proposal = OSS_Utilities.fetchProposal(path);
			} catch (IOException iox) {
			    System.err.println("Skipping Proposal: "+path.toString()+
					       " Error fetching from Database: "+iox);	
			    continue;
			}		
			
			if (proposal == null)
			    continue;
			
			if (proposal.getActivationDate() > sod ||
			    proposal.getExpiryDate() < sod) 
			    continue;
			
			if (proposal.getUsedTime() >= proposal.getAllocatedTime())
			    continue;
			
			
			System.err.println("Using proposal: "+proposal);
			Iterator iGroup = proposal.listAllGroups();
			while (iGroup.hasNext()) {
			    
			    Group group = (Group)iGroup.next();
			    
			    double gx = group.getNominalExecutionTime();
			    
			    
			    // Now check we are able to do group today
			    
			    if (group.getExpiryDate() < sod)
				continue;
			    
			    // work out visibility now (but only during darkness period)
			    double vis = 0.0;
			    long tt = sod;
			    while (tt < sod + 86400*1000L) {	
				if (cando(group, tt)) {
				    double sunElev = sun.getAltitude(tt, site);
				    if (sunElev < Math.toRadians(-18.0)) {
					vis += 60000.0;
				    }
				}
				tt += 60000L;
			    }
				
			    System.err.println("Found visible group: "+group.getFullPath()+" Exec = "+(gx/1000)+" S, VISFRAC = "+(vis/lnight));
			    
			    if (group instanceof MonitorGroup) {
				// MONITOR
				
				if (((MonitorGroup)group).getStartDate() > sod)
				    continue;
				if (((MonitorGroup)group).getEndDate() < sod)
				    continue;
				double period = (double)((MonitorGroup)group).getPeriod();
				double nw = vis / period;
			
				updateHist(rah, group, nw);
				
			    } else if 
				  (group instanceof RepeatableGroup) {
				// MIN INTERVAL
				if (((RepeatableGroup)group).getStartDate() > sod)
				    continue;
				if (((RepeatableGroup)group).getEndDate() < sod)
				    continue;
				
				double minint = (double)((RepeatableGroup)group).getMinimumInterval();
				double nw = vis / minint;
			
				updateHist(rah, group, nw);

			    } else if
				  (group instanceof EphemerisGroup) {
				// EPHEMERIS  
				if (group.isDone())
				    continue;
				if (((EphemerisGroup)group).getStart() > sod)
				    continue;
				if (((EphemerisGroup)group).getEnd() < sod)
				    continue;
				
				updateHist(rah, group, vis/lnight);
				
			    } else if
				  (group instanceof FixedGroup) {
				// FIXED
				
				long fgt = ((FixedGroup)group).getFixedTime();
				if (fgt < sod || fgt > sod+86400*1000L)
				    continue;
								
				updateHist(rah, group, 1);

			    } else {
				// FLEXIBLE
				
				if (group.isDone())
				    continue;
				// check its out of date...
				if (group.getStartingDate() > sod ||
				    group.getExpiryDate() < sod)
				    continue;
				
				// no nights left...
				double nrn = (double)(group.getExpiryDate() - sod)/86400000.0;
				// note we get just a fraction contribution
			
				updateHist(rah, group, nrn);

			    }
			    
			} // next Group
			
		    } // next Proposal
		    
		} // next User
		
	    } // next TAG
	    
	    for (int k = 0; k < 36; k++) {
		double radeg = 10.0*k;
		double rahrs = radeg/15.0;
		System.err.println("RA "+rahrs+" XT= "+rah[k]);
	    }

	} catch (Exception e) {
	    e.printStackTrace();
	    return;
	}
    }

    /** check all targets visible.*/
    private static boolean cando(Group group, long now) {

	// check target visibility.
	Iterator it = group.listAllObservations();
	while (it.hasNext()) {
	    Observation obs = (Observation)it.next();
	    if (obs != null) {
		Source source = obs.getSource();
		Position target = source.getPosition();
		if (target.getAltitude(now) < Math.toRadians(22.0))
		    return false;
	    }
	}

	return true;
	
    }
        
    private static void updateHist(double[] ras, Group group, double xt) {

	double nobs = (double)group.getObservations().size();
	Iterator it = group.listAllObservations();
	while (it.hasNext()) {
	    Observation obs = (Observation)it.next();
	    if (obs != null) {
		Source source = obs.getSource();
		Position target = source.getPosition();
		double ra = target.getRA();

		int rai = (int)Math.floor(Math.toDegrees(ra)/10.0);
		
		ras[rai] += xt/nobs;
	    }
	}


    }


}
